import {director} from "cc";
import {WorldEvent} from "db://assets/script/common/events/world-event";
import {GameEvent} from "db://assets/script/game-event";
import {WorldPubSubServer} from "db://assets/script/common/pubsub/world-pub-sub-server";

export class WorldPubSubSubscriber {
    private _topic: string
    private _handler: (event: WorldEvent, subscriber: any) => Promise<any>
    private _server: WorldPubSubServer
    private _subscriber: any
    private _autoAck: boolean

    constructor(topic: string, autoAck: boolean, server: WorldPubSubServer, handler: (event: WorldEvent, subscriber: any) => Promise<any>, subscriber: any) {
        this._topic = topic
        this._server = server
        this._handler = handler
        this._autoAck = autoAck
        this._subscriber = subscriber
        this._server.subscribe(topic)
        director.on(GameEvent.worldPubSubAckCompletePrefix + this._topic, this._consume, this);
        director.on(GameEvent.worldPubSubMessageArrivedPrefix + this._topic, this._consume, this);
    }

    private _consume(_: number) {
        const event = this._server.pullSingle(this._topic)
        if (!event) return
        this._handler(event, this._subscriber)
            .finally(() => {
                if (this._autoAck) this.ack()
            })
    }

    ack() {
        director.emit(GameEvent.worldPubSubAck, this._topic);
    }

    unsubscribe() {
        director.off(GameEvent.worldPubSubAckCompletePrefix + this._topic, this._consume, this);
        director.off(GameEvent.worldPubSubMessageArrivedPrefix + this._topic, this._consume, this);
    }

    subscribe(topic: string) {
        this._topic = topic
        this._server.subscribe(topic)
        director.on(GameEvent.worldPubSubAckCompletePrefix + this._topic, this._consume, this);
        director.on(GameEvent.worldPubSubMessageArrivedPrefix + this._topic, this._consume, this);
    }

    publish(event: WorldEvent) {
        this._server.publish(this._topic, event)
    }

}